Skip to content

fix(api): harden task automations for MCP/API clients#3044

Merged
tofikwest merged 3 commits into
mainfrom
fix/mcp-automation-hardening
Jun 5, 2026
Merged

fix(api): harden task automations for MCP/API clients#3044
tofikwest merged 3 commits into
mainfrom
fix/mcp-automation-hardening

Conversation

@tofikwest
Copy link
Copy Markdown
Contributor

@tofikwest tofikwest commented Jun 5, 2026

What & why

Three related hardening fixes for the task automation endpoints — the ones customers reach through the MCP server. Surfaced while triaging Nicole's report (automations behaving badly over MCP). Each is small and safe; none changes the web UI flow.

1. create-version returned a raw 500 on a bad body → now a clean 4xx

POST /v1/tasks/{taskId}/automations/{automationId}/versions used an inline, untyped @Body(). The global ValidationPipe can't see an inline type, so a request missing version/scriptKey sailed through to Prisma and threw a non-null constraint violation → 500. It was also invisible in the OpenAPI spec (no documented request body).

  • Added CreateVersionDto (validated with class-validator, documented with @ApiProperty + @ApiBody). Missing/invalid fields now fail at validation → 400.
  • Wrapped the service in defense-in-depth Prisma error mapping: duplicate (automation, version)409 Conflict; missing automation (FK P2003 / P2025) → 404 Not Found. Unexpected errors are rethrown untouched (no masking real 500s).

2. The MCP server could hang forever on a slow call → finite request timeout

Speakeasy-generated request functions resolve their timeout to operationTimeoutMs || clientTimeoutMs || -1, and -1 means "no timeout". A slow/hung upstream call left the MCP server's fetch dangling indefinitely; the client eventually marked the whole connection unhealthy (the wedging customers saw).

  • Set x-speakeasy-timeout: 120000 at the OpenAPI document root, both in the generator (applyPublicOpenApiMetadata) and surgically in openapi.json. The SDK now aborts a stuck request and returns a clean error instead of hanging.
  • 120s comfortably covers our slowest endpoints while staying under the ALB's 300s idle timeout (comp-private infra/modules/loadbalancer.ts).

3. Automation-authoring tools are dead-ends over MCP → hidden from the MCP surface

Creating a working automation requires generating its evidence-collection script, and that step lives only in the enterprise-api browser chat (an AI tool writes .draft.js to S3; publish copies it to .vN.js). Neither the public API nor MCP can produce that script. So over MCP, create-automation and create-version only ever create an empty shell + a version row pointing at a script that was never generated — a dead end that confuses agents.

  • Disabled both tools via the generation overlay (x-speakeasy-mcp.disabled: true). The HTTP endpoints stay live for the web UI, which drives the full flow. Read/list/update automation tools remain available over MCP.
  • This is the agreed interim: hide the dead-end until script generation is exposed as a first-class (async) endpoint, rather than returning an error the agent has to interpret.

Tests

  • automations.service.spec.ts — createVersion success + P2002→409, P2003/P2025→404, unexpected→rethrow.
  • create-version.dto.spec.ts — DTO rejects missing version/scriptKey, version < 1, empty scriptKey; changelog optional.
  • openapi-docs.spec.ts — asserts the document root carries x-speakeasy-timeout.
  • All 12 pass. The existing /v1/policies "SOC 2" SEO-copy assertion in openapi-docs.spec.ts fails on main already (curated copy drifted in d8ce45093) — unrelated to this PR.

Notes for the reviewer

🤖 Generated with Claude Code


Summary by cubic

Hardens task automation endpoints for MCP/API: adds input validation to prevent 500s, sets a 120s SDK/MCP request timeout to avoid hangs, and hides dead-end automation creation over MCP.

  • Bug Fixes
    • create-version: use CreateVersionDto with OpenAPI body; reject missing/invalid fields and whitespace-only scriptKey; map Prisma P2002→409 and P2003/P2025→404; unexpected errors rethrow.
    • Add x-speakeasy-timeout: 120000 at the OpenAPI root so generated SDK/MCP calls abort instead of hanging; under the ALB’s 300s idle timeout.
    • Disable MCP actions for creating automations and versions via x-speakeasy-mcp.disabled; HTTP endpoints remain for the web UI.

Written for commit 56c42df. Summary will update on new commits.

Review in cubic

Three related hardening fixes for the automation endpoints that customers
hit through the MCP server.

1. create-version no longer 500s on a malformed body. The endpoint used an
   inline, untyped @Body() that the global ValidationPipe could not see, so a
   missing version/scriptKey reached Prisma and threw a non-null violation
   (raw 500). Add a validated, documented CreateVersionDto and map Prisma
   failures to clean responses: duplicate version -> 409, missing -> 404.

2. Bake a finite default request timeout (x-speakeasy-timeout = 120s) into the
   generated SDK and MCP server. Without it the generated request functions
   resolve their timeout to -1 ("no timeout"), so a hung upstream call leaves
   the MCP fetch dangling forever and the client marks the whole connection
   unhealthy. 120s covers our slowest endpoints while staying under the ALB's
   300s idle timeout.

3. Hide the two automation-authoring tools (create-automation, create-version)
   from the MCP surface. A working automation needs its evidence script
   generated, and that step lives only in the enterprise-api browser chat, so
   over MCP these POSTs only ever create an empty shell plus a version row
   pointing at a script that was never generated. Disable them via the
   generation overlay until script generation is a first-class endpoint; the
   HTTP endpoints stay live for the web UI.

openapi.json is edited surgically (root key only) to avoid clobbering the open
uploads PR (#3042); the full create-version body appears on the next regen.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
app Ready Ready Preview, Comment Jun 5, 2026 3:29pm
comp-framework-editor Ready Ready Preview, Comment Jun 5, 2026 3:29pm
portal Ready Ready Preview, Comment Jun 5, 2026 3:29pm

Request Review

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 9 files

Confidence score: 4/5

  • This PR is likely safe to merge with minimal risk, since the only reported issue is moderate in severity (5/10) and limited to DTO input validation.
  • In apps/api/src/tasks/automations/dto/create-version.dto.ts, scriptKey currently allows whitespace-only values, which can let invalid keys pass validation and lead to avoidable downstream handling errors.
  • Because the impact is concrete but scoped to one validation path (not a clear system-wide break), this is better treated as a follow-up fix than a merge blocker.
  • Pay close attention to apps/api/src/tasks/automations/dto/create-version.dto.ts - tighten scriptKey validation to reject blank/whitespace-only input.

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread apps/api/src/tasks/automations/dto/create-version.dto.ts
@mintlify
Copy link
Copy Markdown
Contributor

mintlify Bot commented Jun 5, 2026

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
CompAI 🟢 Ready View Preview Jun 5, 2026, 3:11 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

tofikwest and others added 2 commits June 5, 2026 11:24
@isnotempty() treats a whitespace-only string ("   ", "\t\n") as valid, so a
blank scriptKey could pass validation and persist a version row whose script
can never be fetched at runtime. Trim the value first (type-guarded so
non-strings still hit @IsString) so a blank collapses to "" and @isnotempty
rejects it; legitimate keys are normalized.

Issue identified by cubic on PR #3044.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rdening

# Conflicts:
#	apps/mcp-server/.speakeasy/mcp-uploads-overlay.yaml
@claudfuen
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 3.72.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants